package com.z100h.supplychain.evidence.facade.impl;

import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.rribbit.Listener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jeeplus.core.facade.FacadeException;
import com.jeeplus.core.persistence.Page;
import com.jeeplus.modules.sys.entity.User;
import com.jeeplus.modules.sys.security.UsernamePasswordToken;
import com.jeeplus.modules.sys.utils.UserUtils;
import com.z100h.supplychain.core.EvidenceLockState;
import com.z100h.supplychain.core.EvidenceState;
import com.z100h.supplychain.core.EvidenceType;
import com.z100h.supplychain.core.ResourceStockoutLockState;
import com.z100h.supplychain.core.ScEventServiceType;
import com.z100h.supplychain.core.ScEventType;
import com.z100h.supplychain.core.biz.entity.CommonEvidence;
import com.z100h.supplychain.core.biz.entity.Resource;
import com.z100h.supplychain.core.process.AbstractReceiptProcess;
import com.z100h.supplychain.evidence.entity.ScEvent;
import com.z100h.supplychain.evidence.entity.WarehouseReceipt;
import com.z100h.supplychain.evidence.entity.WarehouseReceiptVO;
import com.z100h.supplychain.evidence.facade.WarehousingFacade;
import com.z100h.supplychain.evidence.service.ScEventService;
import com.z100h.supplychain.evidence.service.WarehouseReceiptService;
import com.z100h.supplychain.purchase.entity.PurchaseOrderItemActual;
import com.z100h.supplychain.purchase.entity.PurchaseOrderItemActualVo;
import com.z100h.supplychain.purchase.service.PurchaseOrderItemActualService;
import com.z100h.supplychain.purchase.service.PurchaseOrderService;
import com.z100h.supplychain.sku.entity.SkuAmount;
import com.z100h.supplychain.warehouse.service.WarehouseService;

@Service
public class WarehousingFacadeImpl extends AbstractReceiptProcess<WarehouseReceipt>
		implements WarehousingFacade<WarehouseReceipt> {

	@Autowired
	private PurchaseOrderService purchaseOrderService;

	@Autowired
	private WarehouseReceiptService warehouseReceiptService;

	@Autowired
	private PurchaseOrderItemActualService purchaseOrderItemActualService;

	@Autowired
	private ScEventService scEventService;

	@Autowired
	private WarehouseService warehouseService;

	@Override
	public String createWarehouseReceipt(WarehouseReceipt warehouseReceipt) throws Throwable {
		try {
			warehouseReceipt.setReceiptType(EvidenceType.PURCHASERECEIPT.getType());
			this.preCreateProcess(warehouseReceipt);
			return warehouseReceipt.getEvidenceId();
		} catch (Throwable e) {
			logger.error("createEvidence is error.");
			throw new FacadeException(e.getMessage());
		}
	}

	/**
	 * 模板抽象方法
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.core.process.AbstractReceiptProcess#createEvidence(com.z100h.supplychain.core.Evidence, com.z100h.supplychain.core.EvidenceState)
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年4月9日 上午11:17:28
	 */
	@Override
	@Transactional(readOnly = false)
	protected String createEvidence(WarehouseReceipt evidence, EvidenceState evidenceState) {

		CommonEvidence commonEvidence = null;
		String id = null;
		try {

			if (evidence.getReceiptType().equals(EvidenceType.RECEIPT.getType())) {
				commonEvidence = new CommonEvidence(EvidenceType.RECEIPT, evidenceState);
			}

			if (evidence.getReceiptType().equals(EvidenceType.PURCHASERECEIPT.getType())) {
				commonEvidence = new CommonEvidence(EvidenceType.PURCHASERECEIPT, evidenceState);
			}
			if (evidence.getReceiptType().equals(EvidenceType.CHECKRECEIPT.getType())) {
				commonEvidence = new CommonEvidence(EvidenceType.CHECKRECEIPT, evidenceState);
			}

			// 插入主表凭证
			commonEvidenceService.save(commonEvidence);
			// 插入入库单
			evidence.setEvidenceId(commonEvidence.getId());
			evidence.setState(evidenceState.getValue().toString());
			evidence.setReceiptType(evidence.getReceiptType());
			evidence.preInsert();
			warehouseReceiptService.save(evidence);
			id = commonEvidence.getId();
		} catch (Exception e) {
			logger.error("createEvidence is error.");
			throw new FacadeException(e.getMessage());
		}

		return id;
	}

	/**
	 * 模板抽象方法
	 * 插入转库资源
	 * 
	 * 
	 * 如果 appjson空为小程序 全量质检接口
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.core.process.AbstractReceiptProcess#associateEvidenceWithResource(com.z100h.supplychain.core.Evidence, java.lang.String, com.z100h.supplychain.core.ResourceStockoutLockState)
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年4月9日 上午11:16:14
	 */
	@Override
	@Transactional(readOnly = false)
	protected void associateEvidenceWithResource(WarehouseReceipt warehouseReceipt, String evidenceId,
			ResourceStockoutLockState resourceStockoutLockState) {
		// 获取json
		String appJson = StringEscapeUtils.unescapeHtml4(warehouseReceipt.getJsons());
		JSONArray items = JSONObject.parseArray(appJson);

		if (items != null) {

			try {
				for (int i = 0; i < items.size(); i++) {
					JSONObject objectItem = (JSONObject) items.get(i);
					// 入库明细插入
					PurchaseOrderItemActual orderItem = new PurchaseOrderItemActual();
					orderItem.setSkuId(objectItem.getString("skuId"));
					orderItem.setNum(objectItem.getInteger("num"));
					orderItem.setPrice(objectItem.getBigDecimal("price"));
					orderItem.setWarehouseReceiptId(evidenceId);
					purchaseOrderItemActualService.save(orderItem);
					int num = Integer.parseInt(objectItem.getString("num"));
					for (int j = 0; j < num; j++) {
						Resource resource = new Resource();
						resource.setSkuId(objectItem.getString("skuId"));
						resource.setWarehouseId(warehouseReceipt.getWarehouseId());
						resource.setEvidenceId(evidenceId);
						resource.setEvidenceLock(EvidenceLockState.UNLOCK.getValue());// 默认解锁
						resource.setStockoutLock(resourceStockoutLockState.getValue());// 默认解锁
						resourceService.addResource(resource);// 先插入
					}
				}
			} catch (Exception e) {
				logger.error("associateEvidenceWithResource is error.", e);
				throw new FacadeException("保存异常");
			}

		} else {
			List<PurchaseOrderItemActualVo> itemActualVoList = purchaseOrderItemActualService
					.findPurchaseOrderItemList(evidenceId);

			if (CollectionUtils.isNotEmpty(itemActualVoList)) {
				try {

					for (PurchaseOrderItemActualVo itemVo : itemActualVoList) {

						PurchaseOrderItemActual item = new PurchaseOrderItemActual(itemVo.getSkuId(), itemVo.getPrice(),
								itemVo.getTotalPrice(), itemVo.getAmount(), evidenceId);
						item.setWarehouseReceiptId(evidenceId);
						purchaseOrderItemActualService.save(item);
						int num = item.getNum();
						for (int j = 0; j < num; j++) {
							Resource resource = new Resource();
							resource.setSkuId(item.getSkuId());
							resource.setWarehouseId(warehouseReceipt.getWarehouseId());
							resource.setEvidenceId(evidenceId);
							resource.setEvidenceLock(EvidenceLockState.UNLOCK.getValue());// 默认解锁
							resource.setStockoutLock(resourceStockoutLockState.getValue());// 默认解锁
							resourceService.addResource(resource);// 先插入
						}

					}

				} catch (Exception e) {
					logger.error("associateEvidenceWithResource is error.", e);
					throw new FacadeException("保存异常");
				}
			}
		}

	}

	/**
	 * rfid过机确认接口
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.evidence.facade.WarehousingFacade#confirm(com.z100h.supplychain.evidence.entity.WarehouseReceipt)
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年4月9日 上午11:14:05
	 */
	@Override
	@Transactional(readOnly = false)
	public void confirm(WarehouseReceipt warehouseReceipt) {
		try {
			this.confirmProcess(warehouseReceipt.getResourceIds(), warehouseReceipt.getEvidenceId());
		} catch (Throwable e) {
			logger.error("confirm is error.", e);
			throw new FacadeException(e.getMessage());
		}
	}

	/**
	 * 单子保存接口
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.evidence.facade.WarehousingFacade#save(java.lang.Object)
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年4月9日 上午11:14:28
	 */
	@Override
	@Transactional(readOnly = false)
	public void save(WarehouseReceipt warehouseReceipt) {
		try {
			// 若是采购入库单，保存的时候，存在eid不会走进创建流程，后续
			// warehouseReceipt.setReceiptType(EvidenceType.RECEIPT.getType()); TODO 前台传递的时候 选择类型
			this.createProcess(warehouseReceipt);

			if (warehouseReceipt.getEvidenceId() != null) {// 采购入库单
				// 修改入库单仓库id
				WarehouseReceipt updateWarehouseReceipt = new WarehouseReceipt();
				updateWarehouseReceipt.setEvidenceId(warehouseReceipt.getEvidenceId());
				updateWarehouseReceipt.setWarehouseId(warehouseReceipt.getWarehouseId());
				updateWarehouseReceipt.setRemarks(warehouseReceipt.getRemarks());
				warehouseReceiptService.updateWarehouseReceipt(updateWarehouseReceipt);
			}
		} catch (Throwable e) {
			logger.error("save is error.", e);
			throw new FacadeException(e.getMessage());
		}
	}

	/**
	 * 采购入库快速流程
	 * 入库部分代码，且不包括入库单生成，入库单生成在采购单侧实现业务逻辑
	 * 此处包含逻辑如下
	 * 1.入库单保存，将PurchaseOrderItem写入PurchaseOrderActualItem
	 * 2.入库单根据PurchaseOrderActualItem生成资源写入成品库
	 * 3.根据入库单号批量一次性确认
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.evidence.facade.WarehousingFacade#batchSave(java.lang.Object)
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年4月9日 上午10:07:34
	 */
	@Override
	@Transactional(readOnly = false)
	public void batchSave(WarehouseReceipt warehouseReceipt) {
		try {
			// 创建资源 创建 actual等
			this.createProcess(warehouseReceipt);
			// 修改入库单仓库id
			WarehouseReceipt updateWarehouseReceipt = new WarehouseReceipt();
			updateWarehouseReceipt.setEvidenceId(warehouseReceipt.getEvidenceId());
			updateWarehouseReceipt.setWarehouseId(warehouseReceipt.getWarehouseId());
			updateWarehouseReceipt.setRemarks(warehouseReceipt.getRemarks());
			warehouseReceiptService.updateWarehouseReceipt(updateWarehouseReceipt);
			// 按单子id批量一次性确认
			this.confirmProcess(warehouseReceipt.getEvidenceId());
		} catch (Throwable e) {
			logger.error("save is error.", e);
			throw new FacadeException(e.getMessage());
		}
	}

	/**
	 * 
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.evidence.facade.WarehousingFacade#getWarehouseReceipt(java.lang.Object)
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年4月9日 上午11:16:24
	 */
	@Override
	@Transactional(readOnly = true)
	public WarehouseReceipt getWarehouseReceipt(WarehouseReceipt warehouseReceipt) {
		return warehouseReceiptService.getWarehouseReceipt(warehouseReceipt);
	}

	/**
	 * 
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.evidence.facade.WarehousingFacade#findWarehouseReceiptByPage(com.jeeplus.core.persistence.Page, java.lang.Object)
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年4月9日 上午11:16:45
	 */
	@Override
	@Transactional(readOnly = true)
	public Page<WarehouseReceipt> findWarehouseReceiptByPage(Page<WarehouseReceipt> page,
			WarehouseReceipt warehouseReceipt) {
		return warehouseReceiptService.findWarehouseReceiptByPage(page, warehouseReceipt);
	}

	/**
	 * 
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.evidence.facade.WarehousingFacade#findWarehouseReceiptToResourceByExcel(java.lang.Object)
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年4月9日 上午11:16:49
	 */
	@Override
	@Transactional(readOnly = true)
	public List<WarehouseReceiptVO> findWarehouseReceiptToResourceByExcel(WarehouseReceipt warehouseReceipt) {
		return warehouseReceiptService.findWarehouseReceiptToResourceByExcel(warehouseReceipt);
	}

	@Listener(hint = "SC_BUS_FINISH_PURCHASEORDER")
	@Transactional(readOnly = false)
	public void finishPurchaseOrder(String purchaseOrderServiceId, Boolean ignore, String scUid) throws Throwable {
		try {

			User user = UserUtils.get(scUid);
			if (user == null) {
				throw new Exception("z100htoken中的供应链用户不存在！");
			}
			Subject subject = SecurityUtils.getSubject();
			UsernamePasswordToken token = new UsernamePasswordToken(user.getLoginName(), null, false, null, null, true,
					UsernamePasswordToken._MOBILE_SIGN_CIPHERTEXT);

			try {
				subject.login(token);
			} catch (Exception e) {
			}

			String evidenceId = purchaseOrderService.createWarehouseReceipt(purchaseOrderServiceId, ignore);
			// 直接入库质检完成
			WarehouseReceipt warehouseReceipt = new WarehouseReceipt(evidenceId);
			warehouseReceipt.setJsons(null);
			saveAndQc(warehouseReceipt);
		} catch (

		Exception e) {
			throw new Throwable(e);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.evidence.facade.WarehousingFacade#saveAndQc(java.lang.Object)
	 * @author: Fyh - 1009173473@qq.com 
	 * @date: Created on 2019年9月18日 下午2:45:58
	 */
	@Override
	@Transactional(readOnly = false)
	public void saveAndQc(WarehouseReceipt warehouseReceipt) {
		try {
			if (StringUtils.isBlank(warehouseReceipt.getWarehouseId())) {
				User user = UserUtils.getUser();
				String warehouseId = warehouseService.getWarehouseByCompanyId(user.getCompanyId());
				warehouseReceipt.setWarehouseId(warehouseId);
			}
			// 创建资源 创建 actual等
			this.createProcess(warehouseReceipt);
			// 修改入库单仓库id
			WarehouseReceipt updateWarehouseReceipt = new WarehouseReceipt();
			updateWarehouseReceipt.setEvidenceId(warehouseReceipt.getEvidenceId());
			updateWarehouseReceipt.setWarehouseId(warehouseReceipt.getWarehouseId());
			updateWarehouseReceipt.setRemarks(warehouseReceipt.getRemarks());
			warehouseReceiptService.updateWarehouseReceipt(updateWarehouseReceipt);
			// 按单子id批量一次性确认
			this.confirmProcess(warehouseReceipt.getEvidenceId());

			// 记录质检入库动作
			ScEvent scEvent = new ScEvent(warehouseReceipt.getEvidenceId(), ScEventServiceType.EVIDENCE.getType(),
					ScEventType.FINISHWAREHOUSERECEIPT.getType(), UserUtils.getUser().getId());
			scEventService.insert(scEvent);
		} catch (Throwable e) {
			logger.error("save is error.", e);
			throw new FacadeException(e.getMessage());
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.z100h.supplychain.evidence.facade.WarehousingFacade#save(com.z100h.supplychain.core.EvidenceType, java.lang.String, java.util.List, java.lang.String)
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2020年7月7日 下午2:17:12
	 */
	@Override
	@Transactional(readOnly = false)
	public void save(EvidenceType evidenceType, List<SkuAmount> list, String comment) throws Throwable {

		if (CollectionUtils.isNotEmpty(list)) {
			/**
			 * 1.标准入库内容
			 */
			JSONArray arr = new JSONArray(list.size());
			for (SkuAmount skuAmount : list) {
				JSONObject obj = new JSONObject();
				obj.put("skuId", skuAmount.getSkuId());
				obj.put("num", skuAmount.getAmount());
				obj.put("price", skuAmount.getPrice());
				arr.add(obj);
			}

			/**
			 * 标准入库单实（标准入库单）
			 */
			WarehouseReceipt warehouseReceipt = new WarehouseReceipt(evidenceType);
			warehouseReceipt.preInsert();

			/**
			 * 2.成品库id
			 */
			User user = UserUtils.getUser();
			String warehouseId = warehouseService.getWarehouseByCompanyId(user.getCompanyId());
			warehouseReceipt.setWarehouseId(warehouseId);

			/**
			 * 3.描述
			 */
			warehouseReceipt.setRemarks(comment);
			/**
			 * 对应1.
			 */
			warehouseReceipt.setJsons(arr.toJSONString());

			/**
			 * 1.创建凭据
			 * 2.子表详情
			 */
			this.saveAndQc(warehouseReceipt);
		}

	}

}
